#include "task_handle.h"

#include <QDateTime>
#include <QMetaObject>

#include <utility>

namespace base::tasking {

namespace {
QString normalizeId(const QString& value)
{
    if (!value.isEmpty()) {
        return value;
    }
    return QUuid::createUuid().toString(QUuid::WithoutBraces);
}
} // namespace

TaskHandle::TaskHandle(QString taskId, QString batchId, QObject* parent)
    : QObject(parent)
    , m_taskId(normalizeId(taskId))
    , m_batchId(std::move(batchId))
    , m_cancellationToken(std::make_shared<CancellationToken>())
{
    m_timeoutTimer = new QTimer(this);
    m_timeoutTimer->setSingleShot(true);
    connect(m_timeoutTimer, &QTimer::timeout, this, &TaskHandle::onTimeout);
}

TaskHandle::Ptr TaskHandle::create(const QString& taskId, const QString& batchId, QObject* parent)
{
    return Ptr(new TaskHandle(taskId, batchId, parent), Deleter{});
}

QString TaskHandle::id() const
{
    QMutexLocker locker(&m_mutex);
    return m_taskId;
}

QString TaskHandle::batchId() const
{
    QMutexLocker locker(&m_mutex);
    return m_batchId;
}

TaskHandle::Status TaskHandle::status() const
{
    QMutexLocker locker(&m_mutex);
    return m_status;
}

bool TaskHandle::isCanceled() const
{
    return m_cancellationToken && m_cancellationToken->isCanceled();
}

void TaskHandle::requestCancel()
{
    if (m_cancellationToken) {
        m_cancellationToken->request();
    }
}

CancellationTokenPtr TaskHandle::cancellationToken() const
{
    QMutexLocker locker(&m_mutex);
    return m_cancellationToken;
}

kernel::ErrorCode TaskHandle::errorCode() const
{
    QMutexLocker locker(&m_mutex);
    return m_errorCode;
}

QString TaskHandle::errorMessage() const
{
    QMutexLocker locker(&m_mutex);
    return m_errorMessage;
}

void TaskHandle::setTimeout(int timeoutMs)
{
    QMutexLocker locker(&m_mutex);
    m_timeoutMs = timeoutMs;
}

int TaskHandle::timeout() const
{
    QMutexLocker locker(&m_mutex);
    return m_timeoutMs;
}

void TaskHandle::notifyRunning()
{
    enqueueStatusChange([this]() {
        QMutexLocker locker(&m_mutex);
        if (m_status == Status::Canceled || m_status == Status::Finished) {
            return;
        }
        m_status = Status::Running;
        m_startTime = QDateTime::currentMSecsSinceEpoch();
        locker.unlock();

        startTimeoutTimer();
    });
}

void TaskHandle::notifySuccess(TaskResult result)
{
    enqueueStatusChange([this, result]() {
        stopTimeoutTimer();
        {
            QMutexLocker locker(&m_mutex);
            if (m_status == Status::Canceled) {
                return;
            }
            m_status = Status::Finished;
            m_payload = result.payload;
            m_errorCode = kernel::ErrorCode::Success;
            m_errorMessage.clear();
        }
        emit taskFinished(result);  // 新版统一信号
    });
}

void TaskHandle::notifyFailure(TaskResult result)
{
    enqueueStatusChange([this, result]() {
        stopTimeoutTimer();
        {
            QMutexLocker locker(&m_mutex);
            if (m_status == Status::Canceled) {
                return;
            }
            m_status = Status::Error;
            m_errorCode = result.errorCode;
            m_errorMessage = result.errorMessage;
            m_payload = result.payload;
        }
        emit taskFinished(result);  // 新版统一信号
    });
}

void TaskHandle::notifyCanceled()
{
    enqueueStatusChange([this]() {
        stopTimeoutTimer();
        TaskResult result;
        {
            QMutexLocker locker(&m_mutex);
            // 防止覆盖已完成的状态 (Finished/Error/Timeout)
            if (m_status == Status::Finished || m_status == Status::Error) {
                return;
            }
            m_status = Status::Canceled;
            result.success = false;
            result.errorCode = kernel::ErrorCode::InvalidOperation;
            result.errorMessage = "Task was canceled";
        }
        emit taskFinished(result);  // 新版统一信号
    });
}

void TaskHandle::enqueueStatusChange(std::function<void()> fn)
{
    QMetaObject::invokeMethod(
        this,
        [fn = std::move(fn)]() {
            if (fn) {
                fn();
            }
        },
        Qt::QueuedConnection);
}

void TaskHandle::startTimeoutTimer()
{
    if (!m_timeoutTimer) {
        return;
    }

    QMutexLocker locker(&m_mutex);
    if (m_timeoutMs > 0) {
        m_timeoutTimer->start(m_timeoutMs);
    }
}

void TaskHandle::stopTimeoutTimer()
{
    if (m_timeoutTimer && m_timeoutTimer->isActive()) {
        m_timeoutTimer->stop();
    }
}

void TaskHandle::onTimeout()
{
    enqueueStatusChange([this]() {
        TaskResult result;
        {
            QMutexLocker locker(&m_mutex);
            if (m_status != Status::Running) {
                return;
            }

            qint64 elapsed = QDateTime::currentMSecsSinceEpoch() - m_startTime;
            QString timeoutMsg = QString("Task timed out after %1ms (limit: %2ms)")
                                     .arg(elapsed)
                                     .arg(m_timeoutMs);

            m_status = Status::Error;
            m_errorCode = kernel::ErrorCode::Timeout;
            m_errorMessage = timeoutMsg;

            result.success = false;
            result.errorCode = kernel::ErrorCode::Timeout;
            result.errorMessage = timeoutMsg;
        }

        emit taskFinished(result);  // 新版统一信号
    });
}

void TaskHandle::Deleter::operator()(TaskHandle* handle) const
{
    if (!handle) {
        return;
    }

    auto targetThread = handle->thread();
    auto currentThread = QThread::currentThread();

    if (targetThread && targetThread != currentThread) {
        QMetaObject::invokeMethod(
            handle,
            [handle]() {
                handle->deleteLater();
            },
            Qt::QueuedConnection);
        return;
    }

    handle->deleteLater();
}

} // namespace base::tasking
